using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ByteFarm.ImageMetaData.Format;
using ByteFarm.ImageMetaData.Format.Tiff;

namespace ByteFarm.ImageLibraryBuilder
{
    internal static class Librarian
    {
        public static void Run(DirectoryInfo source, DirectoryInfo target, IEnumerable<string> validExtensions,
                               IEnumerable<string> deleteExtensions)
        {
            TiffInfoProvider infoProvider = new TiffInfoProvider();
            foreach (FileInfo fileInfo in GetFiles(source, validExtensions))
            {
                string dts =
                    infoProvider
                        .GetInfo(fileInfo.FullName)
                        .SelectMany(o => o.DirectoryEntries)
                        .Where(o => o.Tag == Tag.DateTime)
                        .Cast<DirectoryEntry<Tag, FieldType, String>>()
                        .SelectMany(o => o.Values).FirstOrDefault();

                if (String.IsNullOrEmpty(dts))
                    continue;

                int[] parts = dts.Split(':', ' ').Select(o => int.Parse(o)).ToArray();


                DateTime dt = new DateTime(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5]);
                string newpath = GetNewPath(target, dt, fileInfo);
                fileInfo.MoveTo(newpath);
                FileInfo fi = new FileInfo(newpath);
                fi.CreationTime = dt;
                fi.LastAccessTime = DateTime.Now;
            }

            foreach (FileInfo info in GetFiles(source, deleteExtensions))
            {
                info.Delete();
            }

            DeleteEmpty(source);
        }

        private static void DeleteEmpty(DirectoryInfo source)
        {
            foreach (DirectoryInfo info in source.GetDirectories())
            {
                DeleteEmpty(info);
            }

            if (!source.GetFiles().Any() && !source.GetDirectories().Any())
                source.Delete();
        }

        private static string GetNewPath(DirectoryInfo target, DateTime time, FileInfo fileInfo)
        {
            if (!target.Exists)
                target.Create();

            DirectoryInfo year = target.GetDirectories(time.Year.ToString()).FirstOrDefault();
            if (year == null)
                year = target.CreateSubdirectory(time.Year.ToString());

            DirectoryInfo month = year.GetDirectories(time.Month.ToString()).FirstOrDefault();
            if (month == null)
                month = year.CreateSubdirectory(time.Month.ToString());

            string path = Path.Combine(month.FullName, fileInfo.Name);

            if (!File.Exists(path))
                return path;

            string extension = Path.GetExtension(path);

            path = path.Substring(0, path.Length - extension.Length + 1);
            int i = 0;
            while (true)
            {
                string newPath = string.Format("{0}{1}{2}", path, i++, extension);
                if (!File.Exists(newPath))
                    return newPath;
            }
        }


        public static IEnumerable<FileInfo> GetFiles(DirectoryInfo dir, IEnumerable<string> validExtensions)
        {
            return dir.GetDirectories()
                .SelectMany(o => GetFiles(o, validExtensions))
                .Union(
                dir.GetFiles()
                    .Where(
                    o => validExtensions.Any(a => String.Compare(o.Extension, "." + a) == 0)));
        }
    }
}